package com.rs2hd.model;

import com.rs2hd.util.Misc;

/**
 * Handles walking.
 *
 * @author Graham
 */
public class WalkingQueue {

	private class Point {
		private int x;
		private int y;
		private int dir;
	}

	private static final int SIZE = 50;

	public int wQueueReadPtr = 0;
	public int wQueueWritePtr = 0;
	public Point[] walkingQueue = new Point[SIZE];

	private Player player;

	private boolean isRunning = false, isRunToggled = false;

	public boolean isRunToggled() {
		return isRunToggled;
	}

	public void setRunToggled(boolean isRunToggled) {
		this.isRunToggled = isRunToggled;
	}

	public WalkingQueue(Player entity) {
		this.player = entity;
		for (int i = 0; i < SIZE; i++) {
			walkingQueue[i] = new Point();
			walkingQueue[i].x = 0;
			walkingQueue[i].y = 0;
			walkingQueue[i].dir = -1;
		}
		reset();
	}

	public void setIsRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}

	public void reset() {
		walkingQueue[0].x = player.getLocation().getLocalX();
		walkingQueue[0].y = player.getLocation().getLocalY();
		walkingQueue[0].dir = -1;
		wQueueReadPtr = wQueueWritePtr = 1;
	}

	public void addStepToWalkingQueue(int x, int y) {
		int diffX = x - walkingQueue[wQueueWritePtr - 1].x, diffY = y - walkingQueue[wQueueWritePtr - 1].y;
		int dir = Misc.direction(diffX, diffY);
		if (wQueueWritePtr >= SIZE) {
			return;
		}
		if (dir != -1) {
			walkingQueue[wQueueWritePtr].x = x;
			walkingQueue[wQueueWritePtr].y = y;
			walkingQueue[wQueueWritePtr++].dir = dir;
		}
	}

	public void getNextPlayerMovement() {
		player.getSprites().setSprites(-1, -1);
		if (player.getTeleportTo() != null) {
			reset();
			Location lastRegion = player.getLocation();
			int rx = lastRegion.getRegionX();
			int ry = lastRegion.getRegionY();
			player.setLocation(player.getTeleportTo());
			player.resetTeleportTo();
			player.getUpdateFlags().setDidTeleport(true);
			if ((rx - player.getLocation().getRegionX()) >= 4 || (rx - player.getLocation().getRegionX()) <= -4) {
				player.getUpdateFlags().setDidMapRegionChange(true);
			}
			if ((ry - player.getLocation().getRegionY()) >= 4 || (ry - player.getLocation().getRegionY()) <= -4) {
				player.getUpdateFlags().setDidMapRegionChange(true);
			}
		} else {
			Location oldLocation = player.getLocation();
			int walkDir = getNextWalkingDirection();
			int runDir = -1;
			if (isRunning || isRunToggled) {
				if (player.getRunEnergy() > 0) {
					runDir = getNextWalkingDirection();
					if (runDir != -1) {
						player.setRunEnergy(player.getRunEnergy() - 1);
					}
				} else {
					if (isRunToggled) {
						player.getActionSender().sendConfig(173, 0);
						isRunning = false;
					}
					isRunning = false;
				}
			}
			Location lastRegion = player.getUpdateFlags().getLastRegion();
			if (lastRegion != null) {
				int rx = lastRegion.getRegionX();
				int ry = lastRegion.getRegionY();
				if ((rx - player.getLocation().getRegionX()) >= 4) {
					player.getUpdateFlags().setDidMapRegionChange(true);
				} else if ((rx - player.getLocation().getRegionX()) <= -4) {
					player.getUpdateFlags().setDidMapRegionChange(true);
				}
				if ((ry - player.getLocation().getRegionY()) >= 4) {
					player.getUpdateFlags().setDidMapRegionChange(true);
				} else if ((ry - player.getLocation().getRegionY()) <= -4) {
					player.getUpdateFlags().setDidMapRegionChange(true);
				}
			} else {
				player.getUpdateFlags().setDidMapRegionChange(true);
			}
			if (player.getUpdateFlags().didMapRegionChange()) {
				if (walkDir != -1) {
					wQueueReadPtr--;
				}
				if (runDir != -1) {
					wQueueReadPtr--;
				}
				walkDir = -1;
				runDir = -1;
				player.setLocation(oldLocation);
			}
			player.getSprites().setSprites(walkDir, runDir);
		}
	}
	public void GoTo(Player p, int CoordX, int CoordY) {
		if(player.frozen > 0) {
			player.getActionSender().sendMessage("You are frozen!");
			player.getWalkingQueue().reset();
			return;
		}
		player.getWalkingQueue().reset();
		int toX = CoordX  -  (p.getLocation().getRegionX() - 6) * 8;
		int toY = CoordY  -  (p.getLocation().getRegionY() - 6) * 8;
		int[][] path = findRoute(p, toX, toY);
			if(path != null) {
			for(int i=0; i<path.length; i++) {
				addToWalkingQueueFollow(path[i][0], path[i][1]);
			}
		}
	}
    
	public void addToWalkingQueue(int x, int y) {
		int diffX = x - walkingQueue[wQueueWritePtr - 1].x, diffY = y - walkingQueue[wQueueWritePtr - 1].y;
		int max = Math.max(Math.abs(diffX), Math.abs(diffY));
		for (int i = 0; i < max; i++) {
			if (diffX < 0)
				diffX++;
			else if (diffX > 0)
				diffX--;
			if (diffY < 0)
				diffY++;
			else if (diffY > 0)
				diffY--;
			addStepToWalkingQueue(x - diffX, y - diffY);
		}
	}
	public void addToWalkingQueueFollow(int x, int y) {
			int diffX = x - walkingQueue[wQueueWritePtr - 1].x, diffY = y - walkingQueue[wQueueWritePtr - 1].y;
			int max = Math.max(Math.abs(diffX), Math.abs(diffY));
			for (int i = 0; i < max; i++) {
				if (diffX < 0)
					diffX++;
				else if (diffX > 0)
					diffX--;
				if (diffY < 0)
					diffY++;
				else if (diffY > 0)
					diffY--;
				int toQueX = x - diffX;
				int toQueY = y - diffY;
				if (toQueX != x || toQueY != y)
					addStepToWalkingQueue(toQueX, toQueY);
			}
	}	
	private int[][] findRoute(Player p, int toX, int toY) {
		return new int[][] { new int[] { toX, toY } };
	}

	private int getNextWalkingDirection() {
		if (wQueueReadPtr == wQueueWritePtr) {
			return -1;
		}
		int dir = walkingQueue[wQueueReadPtr++].dir;
		int xdiff = Misc.DIRECTION_DELTA_X[dir];
		int ydiff = Misc.DIRECTION_DELTA_Y[dir];
		Location newLocation = Location.location(player.getLocation().getX() + xdiff, player.getLocation().getY() + ydiff, player.getLocation().getZ());
		player.setLocation(newLocation);
		return dir;
	}

	public boolean isRunning() {
		return isRunning;
	}

}
